package com.payment.service.alast.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.payment.config.datasource.DataSource;
import com.payment.config.dto.StringOutputConstant;
import com.payment.entity.alast.common.PartnerPackage;
import com.payment.entity.alast.common.PartnerSpecialDeviceLifecycle;
import com.payment.entity.alast.common.ServicePlanOrderRecord;
import com.payment.entity.purchase.request.RequestPurchaseService;
import com.payment.entity.purchase.response.ResponsePurchaseService;
import com.payment.mapper.alast.PaymentAndResultMapper;
import com.payment.utils.Constant;
import com.payment.utils.HttpUtil;
import com.payment.utils.date.DateUtil;
import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 支付结果到达服务器之后需要做的事情
 *
 * @author lm
 * @date 2020/9/19 1:15
 */
@Component
public class AfterPayDeal {

    private static Logger logger = Logger.getLogger(AfterPayDeal.class);

    private static final String UN_RE_ORDER = "un_re_order:";
    @Autowired
    private RedisTemplate redisTemplate;
    @Resource
    PaymentAndResultMapper paymentAndResultMapper;

    /**
     * 去订购套餐的路径：分测试路径和正式路径，在配置文件这边一起管理
     */
    @Value("${purchase.url}")
    private String PURCHASE_URL;

    /**
     * 将微信支付结果交易编码放入到redis队列中
     *
     * @param payId
     */
    public void addPayIdToRedis(String payId) {
        redisTemplate.opsForValue().set(UN_RE_ORDER + payId, payId, 7, TimeUnit.DAYS);
        logger.info(payId + ":作为值放入成功");
    }

    /**
     * 在这边我们先把payId拿着去数据库把数据拿出来确定数据该走哪条路
     *
     * @param payId
     * @return
     */
    @DataSource(name = "second")
    public String deal(String payId) {
        if (StringUtils.isBlank(payId)) {
            return StringOutputConstant.CODE_FAIL;
        }
        //去数据取出当前这条订单号对应的mark的值
        String mark = paymentAndResultMapper.queryMark(payId);
        boolean b1 = StringUtils.isBlank(mark) || (!StringOutputConstant.CODE_ZERO.equals(mark) && !StringOutputConstant.CODE_ONE.equals(mark));
        if (b1) {
            return StringOutputConstant.CODE_FAIL;
        }
        //mark=0卡片归属领科,去订购套餐
        if (StringOutputConstant.CODE_ZERO.equals(mark)) {
            return purchasePlan(payId, mark);
        }
        //mark=0卡片非领科,去做生命周期的入库
        if (StringOutputConstant.CODE_ONE.equals(mark)) {
            return insertSpecialDevice(payId, mark);
        }
        return StringOutputConstant.CODE_FAIL;
    }

    /**
     * 去调接口订购套餐
     *
     * @param payId
     */
    @DataSource(name = "second")
    public String purchasePlan(String payId, String mark) {

        //去数据库匹配这条订单
        List<ServicePlanOrderRecord> orderList = paymentAndResultMapper.queryOrderRecordList(payId, mark);
        if (null == orderList || orderList.isEmpty()) {
            return StringOutputConstant.CODE_FAIL;
        }
        for (ServicePlanOrderRecord record : orderList) {
            String secret = paymentAndResultMapper.findSecretByPartnerCode(record.getPartnerCode());
            String buyType = "";
            String priceType = "";
            //校验ServicePlanOrderRecord和secret参数
            if (!checkParam(record, secret)) {
                continue;
            }
            //根据渠道编码和套餐编码去遍历套餐的付费方式或者定价方式参数
            List<PartnerPackage> dataList = queryType(record.getPartnerCode(), record.getPackageCode());
            if (!checkPartnerPackage(dataList)) {
                logger.info("");
                continue;
            }
            for (PartnerPackage type : dataList) {
                if (StringUtils.isNotBlank(type.getBuyType())) {
                    buyType = type.getBuyType();
                }
                if (StringUtils.isNotBlank(type.getPriceType())) {
                    priceType = type.getPriceType();
                }
            }
            //現在去把去做订购的参数需要的参数拼成对象
            RequestPurchaseService request = formParamTeam(record, secret, buyType, priceType);
            //去调接口订购套餐
            ResponsePurchaseService response = purchaseServicePlan(request);

            if (null != response && response.getRetCode() != null) {
                if (StringUtils.isNotBlank(response.getRetCode())) {
                    if (Constant.RET_CODE_0000.equals(response.getRetCode())) {
                        logger.info(record.getOrderNo() + "【订购套餐】成功:" + response.getResultInfo());
                        //查询当前这个订单还有没有未去订购的套餐isRequest=0表示没有2去订购过
                        Integer purchasePlanCount = queryNotPurchaseCount(payId);
                        if (purchasePlanCount > 0) {
                            continue;
                        }
                        return StringOutputConstant.CODE_SUCCESS;
                    } else {
                        logger.info((record.getOrderNo() + "【订购套餐】失败：" + response.getResultInfo()));
                        continue;
                    }
                }
            }
        }
        //所有失败的情况
        return StringOutputConstant.CODE_FAIL;
    }

    /**
     * 查询当前这个订单还有没有未去订购的套餐isRequest=0表示没有2去订购过
     *
     * @param payId
     * @return
     */
    private Integer queryNotPurchaseCount(String payId) {

        return paymentAndResultMapper.queryNotPurchaseCount(payId);
    }

    /**
     * 根据渠道编码和套餐编码去遍历套餐的付费方式或者定价方式参数
     *
     * @param partnerCode
     * @param packageCode
     * @return
     */
    private List<PartnerPackage> queryType(String partnerCode, String packageCode) {
        return paymentAndResultMapper.queryType(partnerCode, packageCode);
    }

    /**
     * 验证PartnerPackage参数
     *
     * @param dataList
     * @return
     */
    private boolean checkPartnerPackage(List<PartnerPackage> dataList) {
        boolean flag = true;
        if (null == dataList || dataList.isEmpty()) {
            flag = false;
        }
        for (PartnerPackage p : dataList) {
            if (StringUtils.isBlank(p.getBuyType()) && StringUtils.isBlank(p.getPriceType())) {
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 验证ServicePlanOrderRecord和secret参数
     *
     * @param record
     * @return
     */
    private boolean checkParam(ServicePlanOrderRecord record, String secret) {
        boolean flag = true;
        if (StringUtils.isBlank(secret)) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPartnerCode())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getDeviceCode())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPackageName())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPackageCode())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPackageType())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getOrderPeriod())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPayUnit())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPayId())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getOrderNo())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPayRst())) {
            flag = false;
        }
        if (StringUtils.isBlank(record.getPayType())) {
            flag = false;
        }
        return flag;

    }

    /**
     * 将做订购的参数需要的参数拼成对象
     *
     * @param record
     * @param secret
     * @param buyType
     * @param priceType
     */
    private RequestPurchaseService formParamTeam(ServicePlanOrderRecord record, String secret, String buyType, String priceType) {
        RequestPurchaseService pur = new RequestPurchaseService();
        pur.setPartnerCode(record.getPartnerCode());
        pur.setSecret(secret);
        pur.setDeviceCode(record.getDeviceCode());
        pur.setPackageName(record.getPackageName());
        pur.setPackageCode(record.getPackageCode());
        pur.setPackageType(record.getPackageType());
        pur.setOrderPeriod(record.getOrderPeriod());
        pur.setAmount(record.getPayUnit());
        pur.setBuyType(buyType);
        pur.setPriceType(priceType);
        pur.setPayId(record.getPayId());
        pur.setOrderNo(record.getOrderNo());
        pur.setPayRst(record.getPayRst());
        pur.setPayType(record.getPayType());
        return pur;
    }

    /**
     * 调接口去订购套餐
     *
     * @param request
     * @return
     */
    private ResponsePurchaseService purchaseServicePlan(RequestPurchaseService request) {
        // 开始组装json
        String requestStr = JSON.toJSONString(request);
        logger.info("领科卡【订购套餐】请求：" + requestStr);
        // 发送post请求，并接收返回结果
        String returnStr = HttpUtil.httpPost(PURCHASE_URL, requestStr);
        logger.info("url=" + PURCHASE_URL);

        logger.info("领科卡【订购套餐】响应：" + returnStr);
        ResponsePurchaseService re = JSONArray.parseObject(returnStr, ResponsePurchaseService.class);
        return re;
    }

    /**
     * 卡片不归属领科，就是需要帮忙代收服务费的设备
     * <p>
     * 写新的表：partner_aspecial_device_lifecycle_t ：专门用来记录非领科卡片的生命周期的表
     * <p>
     * 非领科卡片要用一个单独的表记录下来，之后订购动作完成需要完善运营卡片的完整生命周期
     *
     * @param payId
     * @param mark
     */
    @DataSource(name = "second")
    private String insertSpecialDevice(String payId, String mark) {
        //第一步先去查询订单确认是非领科归属的卡片才做之后的动作
        List<ServicePlanOrderRecord> orderList = paymentAndResultMapper.queryOrderRecordList(payId, mark);
        //没有获得这样的订单
        if (null == orderList || orderList.isEmpty()) {
            return StringOutputConstant.CODE_FAIL;
        }
        for (ServicePlanOrderRecord record : orderList) {
            //订购和激活的时间一致就是此刻
            String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            Integer count = querySpecialDevice(record.getPartnerCode(), record.getDeviceCode());
            //没有正在使用的，status直接设为-2正在使用
            if (count < 1) {
                //订单开始时间
                String starDate = date;
                //预计计划结束日期，不是按照自然月，是按照实际的周期加的
                String deadlineDate = DateUtil.deadlineDate(record.getPackageType(), record.getOrderPeriod());
                Integer insertCount = storageSpecialDevice(record, date, starDate, deadlineDate, "2");
                Integer updateCount = updateSpecialDeviceOrderRecord(record, date, deadlineDate, "2");
                if (insertCount > 0 && updateCount > 0) {
                    return StringOutputConstant.CODE_SUCCESS;
                }
            } else {
                //说明有一个正在使用的订单在数据库里，新订的订单只能设为未启用
                Integer insertCount = storageSpecialDevice(record, date, "", "", "1");
                if (insertCount > 0) {
                    return StringOutputConstant.CODE_SUCCESS;
                }
            }
        }
        return StringOutputConstant.CODE_FAIL;
    }


    /**
     * 查询当前设备是否已经有一条正在使用的订单
     *
     * @param partnerCode
     * @param deviceCode
     * @return
     */
    private Integer querySpecialDevice(String partnerCode, String deviceCode) {
        //如果是非领科卡片要用一个单独的表记录下来，之后订购动作完成需要完善运营卡片的完整生命周期，查一下是不是已经有一条正在使用的订单
        return paymentAndResultMapper.querySpecialDevice(partnerCode, deviceCode);
    }

    /**
     * 将特殊的设备生命周期入库
     *
     * @param record
     * @param date
     * @param deadlineDate
     * @param status
     * @return
     */
    private Integer storageSpecialDevice(ServicePlanOrderRecord record, String date, String starDate, String deadlineDate, String status) {
        PartnerSpecialDeviceLifecycle device = new PartnerSpecialDeviceLifecycle();
        device.setDeviceCode(record.getDeviceCode());
        device.setPayId(record.getPayId());
        device.setRequestOrderId(record.getRequestOrderId());
        device.setOrderNo(record.getOrderNo());
        device.setPartnerCode(record.getPartnerCode());
        device.setPartnerName(record.getPartnerName());
        device.setServicePlanShowName(record.getServicePlanShowName());
        device.setServicePlanCode(record.getServicePlanCode());
        device.setPackageCode(record.getPackageCode());
        device.setPackageName(record.getPackageName());
        device.setPackageType(record.getPackageType());
        device.setOrderPeriod(record.getOrderPeriod());
        device.setMark(record.getMark());
        device.setStatus(status);
        device.setPayResultDate(date);
        device.setOrderDate(date);
        device.setOrderStartDate(starDate);
        device.setOrderExpireDate(deadlineDate);
        //先把单独维护的卡片生命周期表入库
        return paymentAndResultMapper.insertSpecialDevice(device);
    }

    /**
     * 去订单记录表里面把特殊的设备的生命周期更新了
     *
     * @param record
     * @param date
     * @param deadlineDate
     * @param status
     * @return
     */
    private Integer updateSpecialDeviceOrderRecord(ServicePlanOrderRecord record, String date, String deadlineDate, String status) {
        Integer count = 0;
        try {
            ServicePlanOrderRecord re = new ServicePlanOrderRecord();
            re.setPayId(record.getPayId());
            re.setRequestOrderId(record.getRequestOrderId());
            re.setDeviceCode(record.getDeviceCode());
            re.setPackageStatus(status);
            re.setOrderTime(new SimpleDateFormat("yyyyMMddHHMMss").format(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date)));
            re.setOrderStartDate(new SimpleDateFormat("yyyyMMdd").format(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date)));
            re.setOrderExpireDate(new SimpleDateFormat("yyyyMMdd").format(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(deadlineDate)));

            //然后将订单记录表中关于订购激活等字段更新了//直接激活
            count = paymentAndResultMapper.updateSpecialDeviceOrderRecord(re);
        } catch (ParseException e) {
            logger.info("时间格式转换失败：" + e);
        }
        return count;
    }

}
